/**
 * Copyright (c) 2008, Andrew Carter
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are 
 * permitted provided that the following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this list of 
 * conditions and the following disclaimer. Redistributions in binary form must reproduce 
 * the above copyright notice, this list of conditions and the following disclaimer in 
 * the documentation and/or other materials provided with the distribution. Neither the 
 * name of Andrew Carter nor the names of contributors may be used to endorse or promote 
 * products derived from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.acarter.scenemonitor.propertydescriptor.definitions;

import com.acarter.propertytable.Property;
import com.acarter.propertytable.PropertySection;
import com.acarter.propertytable.PropertySectionState;
import com.acarter.propertytable.PropertyTable;
import com.acarter.propertytable.propertyobject.BooleanPropertyObject;
import com.acarter.propertytable.propertyobject.EnumPropertyObject;
import com.acarter.propertytable.propertyobject.IntegerPropertyObject;
import com.acarter.propertytable.propertyobject.BooleanPropertyObject.I_BooleanPropertyObjectListener;
import com.acarter.propertytable.propertyobject.EnumPropertyObject.I_EnumPropertyObjectListener;
import com.acarter.propertytable.propertyobject.IntegerPropertyObject.I_IntegerPropertyObjectListener;
import com.acarter.scenemonitor.propertydescriptor.A_PropertyPage;
import com.acarter.scenemonitor.propertydescriptor.enums.E_BoundingVolume;
import com.acarter.scenemonitor.propertydescriptor.enums.E_CullMode;
import com.acarter.scenemonitor.propertydescriptor.enums.E_LightCombine;
import com.acarter.scenemonitor.propertydescriptor.enums.E_SpatialNormalsMode;
import com.acarter.scenemonitor.propertydescriptor.enums.E_TextureCombine;
import com.acarter.scenemonitor.propertydescriptor.propertyobject.QuaternionPropertyObject;
import com.acarter.scenemonitor.propertydescriptor.propertyobject.Vector3fPropertyObject;
import com.acarter.scenemonitor.propertydescriptor.propertyobject.QuaternionPropertyObject.I_QuaternionPropertyObjectListener;
import com.acarter.scenemonitor.propertydescriptor.propertyobject.Vector3fPropertyObject.I_Vector3fPropertyObjectListener;
import com.jme.bounding.BoundingBox;
import com.jme.bounding.BoundingCapsule;
import com.jme.bounding.BoundingSphere;
import com.jme.bounding.BoundingVolume;
import com.jme.bounding.OrientedBoundingBox;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Spatial;

/**
 * @author Carter
 * 
 */
public class SpatialPropertyPage extends A_PropertyPage {

    /**  */
    private Spatial spatial = null;

    /**
     * 
     */
    public SpatialPropertyPage() {

	PropertySection section = new PropertySection("Spatial");
	section.addProperty(new Property("Translation", new Vector3fPropertyObject()));
	section.addProperty(new Property("Rotation", new QuaternionPropertyObject()));
	section.addProperty(new Property("Scale", new Vector3fPropertyObject()));
	section.addProperty(new Property("Bounding Volume", new EnumPropertyObject<E_BoundingVolume>()));
	section.addProperty(new Property("Cull Mode", new EnumPropertyObject<E_CullMode>()));
	section.addProperty(new Property("Light Combine Mode", new EnumPropertyObject<E_LightCombine>()));
	section.addProperty(new Property("Texture Combine Mode", new EnumPropertyObject<E_TextureCombine>()));
	section.addProperty(new Property("Normals Mode", new EnumPropertyObject<E_SpatialNormalsMode>()));
	section.addProperty(new Property("Collidable", new BooleanPropertyObject()));
	section.addProperty(new Property("Z Order", new IntegerPropertyObject()));

	section.setState(PropertySectionState.EXPANDED);

	model.addPropertySection(section);

	section = new PropertySection("Spatial Locks");
	section.addProperty(new Property("Lock Bounds", new BooleanPropertyObject()));
	section.addProperty(new Property("Lock Meshes", new BooleanPropertyObject()));
	section.addProperty(new Property("Lock Shadows", new BooleanPropertyObject()));
	section.addProperty(new Property("Lock Transforms", new BooleanPropertyObject()));
	section.addProperty(new Property("Lock Branch", new BooleanPropertyObject()));

	section.setState(PropertySectionState.EXPANDED);

	model.addPropertySection(section);
    }

    /**
     * @see com.acarter.scenemonitor.propertydescriptor.A_PropertyPage#updateInfo(com.acarter.propertytable.PropertyTableModel,
     *      java.lang.Object)
     */
    @Override
    public void updateModel(PropertyTable table, Object object) {

	if(object instanceof Spatial) {

	    Spatial spatial = (Spatial) object;

	    if(this.spatial == null || !this.spatial.equals(spatial)) {

		this.spatial = spatial;
		updateListeners(spatial);
	    }
	}
    }

    /**
     * 
     * @param table
     * @param object
     */
    @SuppressWarnings("unchecked")
    protected void updateListeners(final Spatial spatial) {

	Vector3fPropertyObject translation = (Vector3fPropertyObject) model.getPropertySection("Spatial").getProperty("Translation")
		.getPropertyObject();

	translation.SetListener(new I_Vector3fPropertyObjectListener() {

	    public Vector3f readValue() {

		return spatial.getLocalTranslation();
	    }

	    public void saveValue(Vector3f value) {

		spatial.setLocalTranslation(value);
	    }
	});

	QuaternionPropertyObject rotation = (QuaternionPropertyObject) model.getPropertySection("Spatial").getProperty("Rotation")
		.getPropertyObject();

	rotation.SetListener(new I_QuaternionPropertyObjectListener() {

	    public Quaternion readValue() {

		return spatial.getLocalRotation();
	    }

	    public void saveValue(Quaternion value) {

		spatial.setLocalRotation(value);
	    }
	});

	Vector3fPropertyObject scale = (Vector3fPropertyObject) model.getPropertySection("Spatial").getProperty("Scale").getPropertyObject();

	scale.SetListener(new I_Vector3fPropertyObjectListener() {

	    public Vector3f readValue() {

		return spatial.getLocalScale();
	    }

	    public void saveValue(Vector3f value) {

		spatial.setLocalScale(value);
	    }
	});

	EnumPropertyObject<E_BoundingVolume> bounding = (EnumPropertyObject<E_BoundingVolume>) model.getPropertySection("Spatial").getProperty(
		"Bounding Volume").getPropertyObject();

	bounding.SetListener(new I_EnumPropertyObjectListener<E_BoundingVolume>() {

	    public E_BoundingVolume readValue() {

		return E_BoundingVolume.getConstant(spatial.getWorldBound());
	    }

	    public void saveValue(E_BoundingVolume value) {

		BoundingVolume bv = null;

		if(value == E_BoundingVolume.BOX)
		    bv = new BoundingBox();
		else if(value == E_BoundingVolume.CAPSULE)
		    bv = new BoundingCapsule();
		else if(value == E_BoundingVolume.SPHERE)
		    bv = new BoundingSphere();
		else if(value == E_BoundingVolume.ORIENTEDBOX)
		    bv = new OrientedBoundingBox();

		spatial.setModelBound(bv);
		spatial.updateModelBound();
	    }
	});

	EnumPropertyObject<E_CullMode> cullHint = (EnumPropertyObject<E_CullMode>) model.getPropertySection("Spatial").getProperty("Cull Mode")
		.getPropertyObject();

	cullHint.SetListener(new I_EnumPropertyObjectListener<E_CullMode>() {

	    public E_CullMode readValue() {

		return E_CullMode.getConstant(spatial.getCullMode());
	    }

	    public void saveValue(E_CullMode value) {

		spatial.setCullMode(value.getType());
	    }
	});

	EnumPropertyObject<E_LightCombine> lightComb = (EnumPropertyObject<E_LightCombine>) model.getPropertySection("Spatial").getProperty(
		"Light Combine Mode").getPropertyObject();

	lightComb.SetListener(new I_EnumPropertyObjectListener<E_LightCombine>() {

	    public E_LightCombine readValue() {

		return E_LightCombine.getConstant(spatial.getLightCombineMode());
	    }

	    public void saveValue(E_LightCombine value) {

		spatial.setLightCombineMode(value.getType());
	    }
	});

	EnumPropertyObject<E_TextureCombine> textureComb = (EnumPropertyObject<E_TextureCombine>) model.getPropertySection("Spatial").getProperty(
		"Texture Combine Mode").getPropertyObject();

	textureComb.SetListener(new I_EnumPropertyObjectListener<E_TextureCombine>() {

	    public E_TextureCombine readValue() {

		return E_TextureCombine.getConstant(spatial.getTextureCombineMode());
	    }

	    public void saveValue(E_TextureCombine value) {

		spatial.setTextureCombineMode(value.getType());
	    }
	});

	EnumPropertyObject<E_SpatialNormalsMode> normalsMode = (EnumPropertyObject<E_SpatialNormalsMode>) model.getPropertySection("Spatial")
		.getProperty("Normals Mode").getPropertyObject();

	normalsMode.SetListener(new I_EnumPropertyObjectListener<E_SpatialNormalsMode>() {

	    public E_SpatialNormalsMode readValue() {

		return E_SpatialNormalsMode.getConstant(spatial.getNormalsMode());
	    }

	    public void saveValue(E_SpatialNormalsMode value) {

		spatial.setNormalsMode(value.getType());
	    }
	});

	BooleanPropertyObject collidable = (BooleanPropertyObject) model.getPropertySection("Spatial").getProperty("Collidable").getPropertyObject();

	collidable.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return spatial.isCollidable();
	    }

	    public void saveValue(boolean value) {

		spatial.setIsCollidable(value);
	    }
	});

	IntegerPropertyObject zOrder = (IntegerPropertyObject) model.getPropertySection("Spatial").getProperty("Z Order").getPropertyObject();

	zOrder.SetListener(new I_IntegerPropertyObjectListener() {

	    public int readValue() {

		return spatial.getZOrder();
	    }

	    public void saveValue(int value) {

		spatial.setZOrder(value);
	    }
	});

	BooleanPropertyObject lockBounds = (BooleanPropertyObject) model.getPropertySection("Spatial Locks").getProperty("Lock Bounds")
		.getPropertyObject();

	lockBounds.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return (spatial.getLocks() & Spatial.LOCKED_BOUNDS) != 0;
	    }

	    public void saveValue(boolean value) {

		if(value)
		    spatial.lockBounds();
		else
		    spatial.unlockBounds();
	    }
	});

	BooleanPropertyObject lockMeshes = (BooleanPropertyObject) model.getPropertySection("Spatial Locks").getProperty("Lock Meshes")
		.getPropertyObject();

	lockMeshes.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return (spatial.getLocks() & Spatial.LOCKED_MESH_DATA) != 0;
	    }

	    public void saveValue(boolean value) {

		if(value)
		    spatial.lockMeshes();
		else
		    spatial.unlockMeshes();
	    }
	});

	BooleanPropertyObject lockShadows = (BooleanPropertyObject) model.getPropertySection("Spatial Locks").getProperty("Lock Shadows")
		.getPropertyObject();

	lockShadows.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return (spatial.getLocks() & Spatial.LOCKED_SHADOWS) != 0;
	    }

	    public void saveValue(boolean value) {

		if(value)
		    spatial.lockShadows();
		else
		    spatial.unlockShadows();
	    }
	});

	BooleanPropertyObject lockTransforms = (BooleanPropertyObject) model.getPropertySection("Spatial Locks").getProperty("Lock Transforms")
		.getPropertyObject();

	lockTransforms.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return (spatial.getLocks() & Spatial.LOCKED_TRANSFORMS) != 0;
	    }

	    public void saveValue(boolean value) {

		if(value)
		    spatial.lockTransforms();
		else
		    spatial.unlockTransforms();
	    }
	});

	BooleanPropertyObject lockBranch = (BooleanPropertyObject) model.getPropertySection("Spatial Locks").getProperty("Lock Branch")
		.getPropertyObject();

	lockBranch.SetListener(new I_BooleanPropertyObjectListener() {

	    public boolean readValue() {

		return (spatial.getLocks() & Spatial.LOCKED_BRANCH) != 0;
	    }

	    public void saveValue(boolean value) {

		if(value)
		    spatial.lockBranch();
		else
		    spatial.unlockBranch();
	    }
	});
    }
}
